using System;
using System.Text.RegularExpressions;

namespace Quiki.ExpressionParsers
{
    public class SimpleInlineExpressionParser : IWikiInlineExpressionParser
    {
        public SimpleInlineExpressionParser (string regexExpression, WikiTextElementType elementType)
        {
            this.elementType = elementType;
            regex = new Regex (regexExpression, RegexOptions.Compiled);
        }

        public SimpleInlineExpressionParser (string regexExpression, Func<string, WikiTextElement> elementConstructor)
        {
            this.elementConstructor = elementConstructor;
            regex = new Regex (regexExpression, RegexOptions.Compiled);
        }

        public void Process (WikiTextElement element)
        {
            if (element.Terminal)
                return;

            if (element.Text != null)
                ProcessText(element);
            else
                ProcessChildElements(element);
        }

        private void ProcessChildElements(WikiTextElement element)
        {
            foreach (WikiTextElement childElement in element.ChildElements)
                Process (childElement);
        }

        private void ProcessText(WikiTextElement element)
        {
            Match match = regex.Match(element.Text);
            if (false == match.Success)
                return;

            int textProcessedLengthSoFar = 0;

            Group elementGroup = match.Groups["element"];
            Group textGroup = match.Groups["text"];

            for (int i = 0; i < elementGroup.Captures.Count; i++)
            {
                Capture elementCapture = elementGroup.Captures[i];
                Capture textCapture = textGroup.Captures[i];

                CreateWikiTextElementFromTextPortion(
                    element,
                    textProcessedLengthSoFar, 
                    elementCapture.Index, 
                    WikiTextElementType.Text);
                CreateWikiTextElementFromTextPortion (
                    element,
                    textCapture.Index,
                    textCapture.Index + textCapture.Length,
                    null);
                textProcessedLengthSoFar = elementCapture.Index + elementCapture.Length;
            }

            CreateWikiTextElementFromTextPortion(
                element, 
                textProcessedLengthSoFar,
                element.Text.Length,
                WikiTextElementType.Text);

            element.Text = null;
        }

        private void CreateWikiTextElementFromTextPortion(
            WikiTextElement parentElement,
            int startIndex, 
            int endIndex, 
            WikiTextElementType? newElementType)
        {
            int length = endIndex - startIndex;
            if (length == 0)
                return;

            string elementText = parentElement.Text.Substring(startIndex, length);

            WikiTextElement element;
            if (newElementType.HasValue)
                element = new WikiTextElement (newElementType.Value, elementText);
            else if (elementConstructor != null)
                element = elementConstructor(elementText);
            else
                element = new WikiTextElement (elementType, elementText);

            parentElement.ChildElements.Add(element);
        }

        private readonly WikiTextElementType elementType;
        private readonly Regex regex;
        private readonly Func<string, WikiTextElement> elementConstructor;
    }
}